/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2013.12.10                                          *
 *                                                                       *
 *************************************************************************/

namespace FreeMAPs
{

template<typename T>
void
LogMessage::unrecognized_enum_item(
    const InputDatabase* db,
    const std::string& key,
    const int num)
{
    FREEMAPS_ASSERT_VALID_POINTER (db);
    db->check_requisite_key (key, DataType::STRING, false, true);
    FREEMAPS_ASSERT_GE (num, 0);
    FREEMAPS_ASSERT_LT (num, db->get_string_vector(key).size());

    std::ostringstream os;
    os << get_line_number_message (db, key) << '\n';
    os << "unrecognized " << key;
    if (db->get_array_size (key) > 1)
    {
        os << "[" << num << "]";
    }

    os << " = \"" << db->get_string_vector (key)[num] << "\"\n";
    os << "the following values are acceptable:\n";

    std::set<std::string> acceptable_values (FreeMAPs::Utilities::get_acceptable_enum_values<T>());
    os << FreeMAPs::Utilities::get_rearranged_set<std::string>(acceptable_values, true, 1) << '\n';

    std::string gauss_value;
    bool has_tip = FreeMAPs::Utilities::get_similar_string(
                       db->get_string_vector (key)[num],
                       acceptable_values,
                       gauss_value,
                       3);
    if (has_tip)
    {
        os << "\ndo you mean \"" << gauss_value << "\" ?" << std::endl;
    }

    FREEMAPS_ERROR (LogMessage::get_log_info (os, ONE_TAB));
}


template<typename T>
std::string
LogMessage::get_log_info(
    const std::string& key,
    const std::set<T>& value,
    const int num_prefix,
    const bool add_quot_mark)
{
    std::ostringstream os;
    os << get_prefix (num_prefix) << key << " = ";
    os << get_log_info (
           Utilities::get_rearranged_set (value, add_quot_mark, /*1*/3),//because num%1 will always be 0, then will have a unnecessary "\n"
           num_prefix + key.size() + 3,
           true);

    return os.str();
}


template<typename T>
std::string
LogMessage::get_log_info(
    const std::string& key,
    const std::vector<T>& value,
    const int num_prefix,
    const bool add_quot_mark)
{
    std::ostringstream os;
    os << get_prefix (num_prefix) << key << " = ";
    os << get_log_info (
           Utilities::get_rearranged_vector (value, add_quot_mark, 1),
           num_prefix + key.size() + 3,
           true);

    return os.str();
}


template<typename T>
std::string
LogMessage::get_log_info(
    const std::string& key,
    const T* value,
    const int count,
    const int num_prefix,
    const bool add_quot_mark)
{
    std::ostringstream os;
    os << get_prefix (num_prefix) << key << " = ";
    os << get_log_info (
           Utilities::get_rearranged_array (value, count, add_quot_mark, 10),
           num_prefix + key.size() + 3,
           true);

    return os.str();
}


template<typename Key, typename Value>
std::string
LogMessage::get_log_info_from_map_keys(
    const std::string& key,
    const std::map<Key, Value>& value,
    const int num_prefix,
    const bool add_quot_mark)
{
    return get_log_info (key, Utilities::get_map_keys (value), num_prefix, add_quot_mark);
}


template<typename Key, typename Value>
std::string
LogMessage::get_log_info_from_map(
    const std::map<Key, Value>& m,
    const int num_prefix,
    const std::string& key,
    const std::string& value,
    const bool add_quot_mark_for_key,
    const bool add_quot_mark_for_value)
{
    std::ostringstream oss;

    std::vector<Key>   keys (m.size());
    std::vector<Value> values (m.size());
    int index = 0;
    for (typename std::map<Key, Value>::const_iterator pos = m.begin();
            pos != m.end(); ++pos, ++index)
    {
        keys   [index] = pos->first;
        values [index] = pos->second;
    }

    oss << get_log_info (key, keys, num_prefix, add_quot_mark_for_key) << '\n';
    oss << get_log_info (value, values, num_prefix, add_quot_mark_for_value);

    return oss.str();
}



template<typename Key, typename Value>
std::string
LogMessage::get_log_info_from_map (
    const std::string& key,
    const std::map<Key, Value>& value,
    const int num_prefix,
    const bool add_quot_mark_for_key,
    const bool add_quot_mark_for_value)
{
    std::ostringstream os;
    os << get_prefix (num_prefix) << key << " = ";
    std::size_t flag_end = 0;
    for (typename std::map<Key, Value>::const_iterator pos = value.begin();
            pos != value.end(); ++pos, ++flag_end)
    {
        if (flag_end > 0)
        {
            os << get_prefix (num_prefix + key.size() + 3);
        }

        os << "[";
        if (add_quot_mark_for_key)
        {
            os << "\"";
        }
        os << pos->first;
        if (add_quot_mark_for_key)
        {
            os << "\"";
        }

        os << ", ";
        if (add_quot_mark_for_value)
        {
            os << "\"";
        }
        os << pos->second;
        if (add_quot_mark_for_value)
        {
            os << "\"";
        }
        os << "]";

        if ((flag_end + 1) < value.size())
        {
            os << ",\n";
        }
    }

    return os.str();
}


template<typename Value>
std::string
LogMessage::get_log_info_from_map (
    const std::string& key,
    const std::map<std::string, Value*>& value,
    const int num_prefix)
{
    std::ostringstream os, oss;

    os << get_log_info_from_map_keys (key, value, num_prefix, true);
    for (typename std::map<std::string, Value*>::const_iterator pos = value.begin();
            pos != value.end(); ++pos)
    {
        oss.str("");
        oss << *pos->second;
        os << "\n\n" << get_log_info (oss, num_prefix);
    }

    return os.str();
}


template<typename Key, typename Value>
std::string
LogMessage::get_log_info_from_pair (
    const std::string& key,
    const std::pair<Key, Value>& value,
    const int num_prefix,
    const bool add_quot_mark_for_key,
    const bool add_quot_mark_for_value)
{
    std::ostringstream os;
    os << get_prefix (num_prefix) << key << " = ";

    os << "[";
    if (add_quot_mark_for_key)
    {
        os << "\"";
    }
    os << value.first;
    if (add_quot_mark_for_key)
    {
        os << "\"";
    }

    os << ", ";
    if (add_quot_mark_for_value)
    {
        os << "\"";
    }
    os << value.second;
    if (add_quot_mark_for_value)
    {
        os << "\"";
    }
    os << "]";

    return os.str();
}

}
